#include "ssd_global.h"

int write_count;
int read_count;

int flash_read_num;
int flash_write_num;
int flash_gc_read_num;
int flash_gc_write_num;
int flash_erase_num;
int flash_oob_read_num;
int flash_oob_write_num;

int map_flash_read_num;
int map_flash_write_num;
int map_flash_gc_read_num;
int map_flash_gc_write_num;
int map_flash_erase_num;
int map_flash_oob_read_num;
int map_flash_oob_write_num;
extern int total_util_sect_num; 
extern int total_extra_sect_num;

/****************************************
 * add by ymb
 ****************************************/
int rqst_cnt;
int translation_read_num = 0;
int translation_write_num = 0;
int cache_cmt_hit = 0;
int cache_scmt_hit = 0;
int cache_slcmt_hit = 0;

/***********************************************************************
 Mapping table
***********************************************************************/
int real_min = -1;
int real_max = 0;

/***********************************************************************
 Cache
***********************************************************************/
int cache_min = -1;
int cache_max = 0;

/***********************************************************************
 *    author: ymb    部分常用变量
 ***********************************************************************/
int init_flag=0;
int MAP_REAL_MAX_ENTRIES= 0 ;
int MAP_GHOST_MAX_ENTRIES= 0 ;
int MAP_SEQ_MAX_ENTRIES= 0 ; 
int MAP_SECOND_MAX_ENTRIES= 0 ; 
int cache_arr[CACHE_MAX_ENTRIES];
int *real_arr = NULL;
int *ghost_arr = NULL;
int *second_arr = NULL;
int *seq_arr = NULL;
int *entry_arr = NULL;
int operation_time = 0;

struct ftl_operation * ftl_op;
int page_num_for_2nd_map_table;

void reset_hit_stat();
void reset_flash_stat();
double calculate_delay_flash();
void initFlash();
void endFlash();
void printWearout();
void send_flash_request(int start_blk_no, int block_cnt, int operation, int mapdir_flag);
void find_real_max();
void find_real_min();
int find_min_ghost_entry();
void synchronize_disk_flash();
void find_min_cache();
double callFsim(unsigned int secno, int scount, int operation);
// Interface between disksim & fsim 
void reset_hit_stat()
{
    rqst_cnt = 0;
    cache_scmt_hit = 0;
    cache_cmt_hit = 0;
    cache_slcmt_hit = 0;
    translation_read_num = 0;
    translation_write_num = 0;
}

void reset_flash_stat()
{
    flash_read_num = 0;
    flash_write_num = 0;
    flash_gc_read_num = 0;
    flash_gc_write_num = 0; 
    flash_erase_num = 0;
    flash_oob_read_num = 0;
    flash_oob_write_num = 0; 
}

/***********************************************************************
 Send request (lsn, sector_cnt, operation flag)
***********************************************************************/

void send_flash_request(int start_blk_no, int block_cnt, int operation, int mapdir_flag)
{
    int size;
    //size_t (*op_func)(sect_t lsn, size_t size);
    size_t (*op_func)(sect_t lsn, size_t size, int mapdir_flag);

    if((start_blk_no + block_cnt) >= total_util_sect_num){
    printf("start_blk_no: %d, block_cnt: %d, total_util_sect_num: %d\n", 
        start_blk_no, block_cnt, total_util_sect_num);
    exit(0);
    }

    if(mapdir_flag == 2){
        if(operation == 0)
            translation_write_num++;
        else
            translation_read_num++;
    }

    switch(operation){
    //write
    case 0:

        op_func = ftl_op->write;
        while (block_cnt> 0) {
            size = op_func(start_blk_no, block_cnt, mapdir_flag);
            start_blk_no += size;
            block_cnt-=size;
        }
        break;
    //read
    case 1:


        op_func = ftl_op->read;
        while (block_cnt> 0) {
            size = op_func(start_blk_no, block_cnt, mapdir_flag);
            start_blk_no += size;
            block_cnt-=size;
        }
        break;

        default: 
        break;
    }
}

void find_real_max()
{
    int i; 

    for(i=0;i < MAP_REAL_MAX_ENTRIES; i++) {
        if(opagemap[real_arr[i]].map_age > opagemap[real_max].map_age) {
            real_max = real_arr[i];
        }
    }
}

void find_real_min()
{
    int i,index; 
    int temp = 99999999;

    for(i=0; i < MAP_REAL_MAX_ENTRIES; i++) {
        if(opagemap[real_arr[i]].map_age <= temp) {
            real_min = real_arr[i];
            temp = opagemap[real_arr[i]].map_age;
            index = i;
        }
    }    
}

int find_min_ghost_entry()
{
    int i; 

    int ghost_min = 0;
    int temp = 99999999; 

    for(i=0; i < MAP_GHOST_MAX_ENTRIES; i++) {
        if(ghost_arr[i]>0)
        {
            if( opagemap[ghost_arr[i]].map_age <= temp) {
            ghost_min = ghost_arr[i];
            temp = opagemap[ghost_arr[i]].map_age;
            }
        }
    }
    // for(i=0; i < MAP_GHOST_MAX_ENTRIES; i++) {
    //     if( opagemap[ghost_arr[i]].map_age <= temp) {
    //     ghost_min = ghost_arr[i];
    //     temp = opagemap[ghost_arr[i]].map_age;
    //     }
    // }
    return ghost_min;
}

void init_arr()
{

    int i;
    for( i = 0; i < MAP_REAL_MAX_ENTRIES; i++) {
        real_arr[i] = -1;
    }
    for( i = 0; i < MAP_GHOST_MAX_ENTRIES; i++) {
        ghost_arr[i] = -1;
    }
    for( i = 0; i < CACHE_MAX_ENTRIES; i++) {
        cache_arr[i] = -1;
    }

}

int search_table(int *arr, int size, int val) 
{
    int i;
    for(i =0 ; i < size; i++) {
        if(arr[i] == val) {
            return i;
        }
    }

    printf("shouldnt come here for search_table()=%d,%d",val,size);
    for( i = 0; i < size; i++) {
    if(arr[i] != -1) {
        printf("arr[%d]=%d ",i,arr[i]);
    }
    }
    exit(1);
    return -1;
}

int find_free_pos( int *arr, int size)
{
    int i;
    for(i = 0 ; i < size; i++) {
        if(arr[i] == -1) {
            return i;
        }
    } 
    printf("shouldnt come here for find_free_pos()");
    exit(1);
    return -1;
}

void find_min_cache()
{
    int i; 
    int temp = 999999;

    for(i=0; i < CACHE_MAX_ENTRIES ;i++) {
        if(opagemap[cache_arr[i]].cache_age <= temp ) {
            cache_min = cache_arr[i];
            temp = opagemap[cache_arr[i]].cache_age;
        }
    }
}

//~处理之后所有的请求映射项都不在CMT中才预取 
int not_in_cache(unsigned int pageno)
{
    int flag = 0;
    
    if((opagemap[pageno].map_status == 0) || (opagemap[pageno].map_status == MAP_INVALID))
        flag=0;
    else if(opagemap[pageno].map_status == MAP_REAL)
        flag=1;
    else
        flag=2;
    
    return flag;
}

